package com.lucun.es_transaction.util;

import cn.hutool.core.util.StrUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.SQLSyntaxErrorException;

public class LuCommonExceptionHandler {
    private static Logger logger = LoggerFactory.getLogger(LuCommonExceptionHandler.class);

    /**
     * 统一处理异常，封装异常反馈信息
     *
     * @param ex 异常
     * @return 例:{"code":"B0341","errorMessage":"No handler found for GET
     * /","data":null}
     */
    public static JsonResult<String> handException(Exception ex) {
        return handException(ex, null);
    }

    /**
     * 统一处理异常，封装异常反馈信息
     *
     * @param ex      异常
     * @param request 请求
     * @return 例:{"code":"B0341","errorMessage":"No handler found for GET
     * /","data":null}
     */
    public static JsonResult<String> handException(Exception ex, HttpServletRequest request) {

        JsonResult<String> r;
        if (ex instanceof BaseException) {
            String code = ((BaseException) ex).getCode();
            r = new JsonResult<>(code, ex.getMessage(), null);
            if (code.startsWith("B")) {
                logger.error("系统执行异常，请求路径：" + getRequestUrl(request), ex);
            } else if (code.startsWith("C")) {
                logger.warn("系统警告", ex);
            }
        } else if (ex instanceof NullPointerException) {
            logger.warn("空指针，请联系系统管理员：" + getRequestUrl(request), ex);
            r = new JsonResult<>("000001", "空指针，请联系系统管理员。", null);
        } else if (ex instanceof NoHandlerFoundException) {
            r = new JsonResult<>("000001", ex.getMessage(), null);
        } else if (ex instanceof HttpMediaTypeNotSupportedException) {
            r = new JsonResult<>("000001", ex.getMessage(), null);
        } else if (ex instanceof ResourceAccessException) {
            logger.warn("服务调用异常，请检查服务节点：" + getRequestUrl(request), ex);
            r = new JsonResult<>("000001", "服务调用异常，请稍后重试。", null);
        } else if (ex instanceof IllegalStateException) {
            String msg = ex.getMessage();
            if (msg.contains("No instances available for")) {
                r = new JsonResult<>("000001", "未查询到服务节点，请稍后重试。" + getRequestUrl(request), null);
            } else {
                r = new JsonResult<>("000001", "服务调用异常，请稍后重试。" + getRequestUrl(request), null);
            }
            logger.warn("服务调用异常，请检查服务节点。", ex);
        } else if (ex instanceof HttpMessageNotReadableException) {
            logger.warn("请求参数格式异常:" + getRequestUrl(request), ex);
            StringBuilder msg = new StringBuilder();
            String errorMessage = ex.getMessage();
            if (errorMessage.contains("JSON parse error")) {
                msg.append("请求参数转换失败，请确认请求参数");
            } else {
                msg.append("请求参数格式异常");
            }
            r = new JsonResult<>("000001", msg.toString(), null);
        } else if (ex instanceof DataIntegrityViolationException
                || ex instanceof SQLIntegrityConstraintViolationException
                || ex instanceof SQLSyntaxErrorException
                || ex instanceof SQLException) {
            logger.error("SQL执行异常:" + getRequestUrl(request), ex);
            String message = ex.getMessage();
            if (StrUtil.containsAnyIgnoreCase(message, "doesn't exist")) {
                message = "SQL执行异常,数据库缺失表，请联系运维人员。";
            } else if (StrUtil.containsAnyIgnoreCase(message, "Unknown column")) {
                message = "SQL执行异常,数据库缺失字段，请联系运维人员。";
            } else if (message.contains("Data too long for column")) {
                message = "数据内容超长,如需扩展请联系管理人员。";
            } else {
                message = "SQL执行异常，请联系开发人员。";
            }
            r = new JsonResult<>("000001", message, null);
        } else {
            String message = ex.getMessage();
            if (StrUtil.containsAny(message, "Unknown column")) {
                message = "SQL执行异常,数据库缺失字段";
            }
            logger.error("系统异常:" + getRequestUrl(request), ex);
            if (StringUtils.isBlank(message)) {
                message = "系统异常,请重试或联系管理人员处理";
            }
            r = new JsonResult<>("000001", message, null);
        }
        r.setData(null);
        if (true) {
            //非开发环境，不反馈堆栈信息
            logger.info("开发环境堆栈信息：", ex);
            StringBuilder tack = new StringBuilder();
            tack.append("开发环境堆栈信息:").append(ex.getMessage()).append(System.lineSeparator());
            for (StackTraceElement element : ex.getStackTrace()) {
                tack.append(element.toString()).append(System.lineSeparator());
            }
            r.setDevTack(tack.toString());
        }
        return r;
    }

    public static String getRequestUrl(HttpServletRequest request) {
        if (request != null && request.getRequestURL() != null) {
            return request.getRequestURL().toString();
        }
        return "";
    }
}
